package com.bluedon.ism.commons.action;

import com.bluedon.ism.commons.SystemContext;
import com.bluedon.ism.commons.entity.Account;
import com.bluedon.ism.commons.operationlog.aspect.OperateLogAnnotation;
import com.bluedon.ism.commons.service.AccountService;
import com.bluedon.ism.commons.service.ConfigService;
import com.bluedon.ism.commons.shiro.UsernamePasswordRealmToken;
import com.bluedon.ism.commons.util.CacheUtil;
import com.bluedon.ism.commons.util.CipherUtil;
import com.bluedon.ism.commons.util.Constants;
import com.bluedon.ism.commons.util.StringUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;

import static com.bluedon.ism.commons.operationlog.LogConstantAdmin.*;

/**
 * 用户登录ACTION
 */
public class LoginAction extends BaseAdminAction {
    
	private static final long serialVersionUID = 1L;

	private static final Log logger = LogFactory.getLog(LoginAction.class);
	
	@Resource(name="accountService")
	private AccountService accountService;
    @Resource(name="cacheManager")
    private CacheManager cacheManager;
    @Resource(name="configService")
    private ConfigService configService;
    
	private Account acc;

	@Transactional
	@OperateLogAnnotation(moduleName=SYSTEM_MANAGER,operateTypeName=SYSTEM_LOGIN,message=PC_SYSTEM_LOGIN,httpMethod="POST")
	public String login() {
		String validSafeCode = configService.getValue("kaptcha_switch");
		request.setAttribute("validSafeCode", validSafeCode);
		if(isGet())
			return INPUT;
		if(isPost()) {
            String cacheKey = acc==null?"tmp":acc.getUsername()+"_pcLoginTimes";
            try{
                Integer lgVal = (Integer) CacheUtil.get(cacheKey);
                if(lgVal!=null&&lgVal>=5){
                    addActionError("登录错误次数过多，请5分钟后重新登录！");
                    return INPUT;
                }
            }catch (Exception e){}

	        Object object = request.getSession().getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
		    if ("on".equals(validSafeCode)&&(object == null || 
		    		!object.toString().equalsIgnoreCase(StringUtil.trimToEmpty(request.getParameter("safecode"))))) {
		        addActionError("验证码错误"); 
		        return INPUT;
		    }
	        request.getSession().removeAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);   
			UsernamePasswordRealmToken token = new UsernamePasswordRealmToken(acc.getUsername(),  CipherUtil.MD5Encode(acc.getPassword()),Constants.ACCOUNT_REALM);
			Subject currentUser = SecurityUtils.getSubject();
            boolean validateResult = false;
            String loginErr = "";
			try {
				currentUser.login(token);
				logger.info("登录用户："+currentUser.getSession().getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY));
				Account account = accountService.getAccountByName(acc.getUsername());
				account.setLoginTime(new Date());
				account.setLoginIp(getIpAddr());
				account.setCountLogin(account.getCountLogin() == null ? 1 : (account.getCountLogin()+1));
				request.getSession().setAttribute(Constants.SESSION_PC_ACCOUNT, account);
				SystemContext systemContext = SystemContext.getContext();
				systemContext.put(SystemContext.CURRENT_ACCOUNT, account);
                validateResult = true;

				logger.debug(currentUser.isPermitted("perm"));
				logger.debug(currentUser.hasRole("市局管理员134"));
				logger.debug(currentUser.isPermitted("系统管理-用户管理-查看"));
				logger.debug(currentUser.hasRole("市局管理员"));
				logger.debug(currentUser.isPermitted("M_181"));
				
			} catch ( AuthenticationException ae ) {
			    loginErr = "登录失败";
			    if (ae instanceof UnknownAccountException){
                    loginErr = "无效用户名/密码";
			    } else if (ae instanceof IncorrectCredentialsException){
                    loginErr = "无效用户名/密码";
			    } else if (ae instanceof LockedAccountException){
                    loginErr = "用户已被锁定";
			    }
			}catch (Exception e){
                loginErr = "登录失败";
            }
            if(!validateResult){
                try{
                    Integer lgVal = (Integer)CacheUtil.get(cacheKey);
                    lgVal = lgVal==null?0:lgVal;
                    lgVal++;
                    if(lgVal>=5){
                        CacheUtil.put(cacheKey,5,300); //加上定时器清除
                        addActionError("登录错误次数过多，请5分钟后重新登录！");
                    }else{
                        CacheUtil.put(cacheKey,lgVal);
                        addActionError(loginErr+"，您还可以尝试"+(5-lgVal)+"次！");
                    }
                } catch (Exception e){}

                return INPUT;
            }
            //在允许的次数内登录成功，清除计数器
            CacheUtil.flush(cacheKey);
			return SUCCESS;
		}
		return INPUT;
	}
	
	@Transactional
	@OperateLogAnnotation(moduleName=SYSTEM_MANAGER,operateTypeName=SYSTEM_LOGOUT,message=PC_SYSTEM_LOGOUT)
	public String loginOut() {
//	    request.getSession().removeAttribute(Constants.SESSION_PC_ACCOUNT); //no need
        Account account = (Account) request.getSession().getAttribute(Constants.SESSION_PC_ACCOUNT);
        request.getSession().removeAttribute(Constants.SESSION_PC_ACCOUNT);
        if (account != null) {
            Cache cache = cacheManager.getCache("menu");
            //清理菜单缓存
            cache.evict("pcmenu"+account.getAid());
            
            Account nAccount = accountService.getAccountById(account.getAid());
            nAccount.setLastSigninTime(account.getLoginTime());
            nAccount.setLastSigninIp(account.getLoginIp());
        }
	    SecurityUtils.getSubject().logout();
	    //request.getSession().invalidate();
	    return SUCCESS;
	}
	
    public void setAccountService(AccountService accountService) {
        this.accountService = accountService;
    }

	public Account getAcc() {
        return acc;
    }

    public void setAcc(Account acc) {
        this.acc = acc;
    }

    public void setCacheManager(CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }

	public void setConfigService(ConfigService configService) {
		this.configService = configService;
	}
    
}
